﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net;
using System.Data.Linq;
using System.Threading.Tasks;
using CrawlerCore;
using HtmlAgilityPack;


namespace WCrawlerLib
{
    /// <summary>
    /// test repository
    /// </summary>
    public partial class Forum
    {
        private LinqDataClassesDataContext dc = new LinqDataClassesDataContext();

        private BrowserSession_Forum _browser;
        public BrowserSession_Forum Browser
        {
            get
            {
                 if (_browser == null)
                    _browser = new BrowserSession_EmptyForum();

                 //*********************************************************************************
                 //INITIALIZE BROWSER SESSION
                 //*********************************************************************************
                 if (ForumTypeId.HasValue 
                     && _browser.ForumTypeId == enumForumType.Unknown)
                 {
                     switch ((enumForumType)ForumTypeId.Value)
                     {
                         case enumForumType.vBulletin:
                             //_browser = new BrowserSession_vBulletin();
                                 _browser = new BrowserSession_EmptyForum();
                             break;
                         case enumForumType.vBulletin3x:
                             _browser = new BrowserSession_vBulletin3x();
                             break;
                         case enumForumType.vBulletin4x:
                             _browser = new BrowserSession_vBulletin4x();
                             break;
                         case enumForumType.phpBB:
                             //_browser = new BrowserSession_phpBB();
                             _browser = new BrowserSession_EmptyForum();
                             break;
                         case enumForumType.phpBB2:
                             _browser = new BrowserSession_phpBB2();
                             break;
                         case enumForumType.phpBB3:
                             _browser = new BrowserSession_phpBB3();
                             break;
                         case enumForumType.IPB:
                             //_browser = new BrowserSession_IPB();
                             _browser = new BrowserSession_EmptyForum();
                             break;
                         case enumForumType.IPB31x:
                             _browser = new BrowserSession_IPB31x();
                             break;
                         case enumForumType.IPB32x:
                             _browser = new BrowserSession_IPB32x();
                             break;
                         case enumForumType.myBB:
                             //_browser = new BrowserSession_myBB();
                             _browser = new BrowserSession_EmptyForum();
                             break;
                     }
                 }
                return _browser;
            }
            set
            {
                _browser = value;
            }
        }

        public bool IsExists(string forumUrl)
        {
            bool result = false;
            
            var obj = from p in dc.Forums
                      where p.ForumUrl.Contains(forumUrl)
                      select p;
            if (obj.Count() > 0)
            {
                result = true;
            }
            return result;
        }

        public bool AddForum(string forumUrl, int groupId, string locationId, string rank, string forumTypeId, string version)
        {
            bool result = false;
            ////LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            if (!IsExists(forumUrl))
            {
                Forum newForum = new Forum();
                newForum.ForumUrl = forumUrl;
                newForum.GroupId = groupId;
                newForum.AccountId = 1;
                newForum.LanguageId = (int)enumLanguage.Unknown;
                newForum.ContentTypeId = (int)enumContentType.Unknown;
                newForum.IsApproved = false;
                if (!string.IsNullOrEmpty(locationId))
                    newForum.LocationId = int.Parse(locationId);
                
                if (!string.IsNullOrEmpty(rank))
                    newForum.AlexaRank = int.Parse(rank);
                
                if (!string.IsNullOrEmpty(forumTypeId))
                    newForum.ForumTypeId = int.Parse(forumTypeId);
                else
                    newForum.ForumTypeId = (int)enumForumType.Unknown;

                if (!string.IsNullOrEmpty(version))
                    newForum.Version = version;

                dc.Forums.InsertOnSubmit(newForum);
                dc.SubmitChanges();
                result = true;
            }
            return result;
        }

        /// <summary>
        /// Add forum list
        /// </summary>
        /// <param name="forumList"></param>
        /// <returns></returns>
        public Dictionary<string, bool> AddForumList(List<string> forumList)
        {
            ////LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            Dictionary<string, bool> resultForumList = new Dictionary<string, bool>();
            foreach (string forumUrl in forumList)
            {
                if (!resultForumList.Keys.Contains(forumUrl))
                {
                    var obj = from p in dc.Forums
                              where p.ForumUrl.Contains(GeneralClass.GetName(forumUrl))
                              select p;
                    if (obj.Count() == 0)
                    {
                        Forum newForum = new Forum();
                        newForum.ForumUrl = forumUrl;
                        newForum.GroupId = 2;
                        newForum.AccountId = 1;
                        newForum.LanguageId = (int)enumLanguage.Unknown;
                        newForum.ForumTypeId = (int)enumForumType.Unknown;
                        newForum.ContentTypeId = (int)enumContentType.Unknown;
                        newForum.IsApproved = false;
                        dc.Forums.InsertOnSubmit(newForum);
                        dc.SubmitChanges();
                        resultForumList.Add(forumUrl, true);
                    }
                    else
                        resultForumList.Add(forumUrl, false);
                    
                }
            }
            return resultForumList;
        }

        public Forum GetForum(int forumId)
        {
            ////LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            Forum f = dc.Forums.Single(c => c.ForumId == forumId);
            return f;
        }

        public IQueryable<Forum> GetAll()
        {
            ////LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            var query = from p in dc.Forums
                        select p;
            return query;
        }

        //public int GetUserId(int forumId)
        //{
        //    ////LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
        //    var query = from p in dc.Forums
        //                where p.ForumId == forumId
        //                select p.UserId;
        //    if (query.Count() > 0)

        //        return query;

        //}

        /// <summary>
        /// Get forums have already posted or not yet posted
        /// </summary>
        /// <param name="postId"></param>
        /// <param name="isPosted"></param>
        /// <returns></returns>
        public IQueryable<Forum> GetPostedForums(int postId, int isPosted)
        {
            ////LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            IQueryable<Forum> query;
            if (isPosted == 0) //if unposted
            {
                query = from p1 in dc.Forums
                        where !(from p2 in dc.ThreadPosts
                                where p2.PostDetail.PostId == postId
                                select p2.ForumThread.ForumId).Contains(p1.ForumId)
                        select p1;
            }
            else if (isPosted == 1) //if posted
            {
                query = from p1 in dc.Forums
                        where (from p2 in dc.ThreadPosts
                               where p2.PostDetail.PostId == postId
                               select p2.ForumThread.ForumId).Contains(p1.ForumId)
                        select p1;
            }
            else //select all
            {
                query = from p in dc.Forums
                        select p;
            }
            return query;
        }

        public void RunSeriveCheckForumInfo()
        {
            ////LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            if (_ForumTypeId != null)
            {
                var query = from p in dc.Forums.AsParallel()
                            where p.ForumTypeId == _ForumTypeId
                            //& p.ForumTypeId != 1 // not vBulletin
                            select p;

                Parallel.ForEach<Forum>(query.AsEnumerable<Forum>(), fr =>
                {
                    CheckForumInfo(fr.ForumId);
                });
            }
            else
            {
                var query = from p in dc.Forums.AsParallel()
                            where p.LanguageId != 16 // not English language
                            select p;

                Parallel.ForEach<Forum>(query.AsEnumerable<Forum>(), fr =>
                {
                    CheckForumInfo(fr.ForumId);
                });
            }
        }

        

        public string GetTagList(ForumTopic objForumTopic, PostDetail objPostDetail)
        {
            //=============================================================================
            //Get Tag list
            //=============================================================================
            //string[] topics = objPostDetail.Post.Topic.TopicName.Split(new char[] { ' ' });
            string[] tags;
            List<string> tagList = new List<string>();
            //Add forum Name if exists
            if (!string.IsNullOrEmpty(objForumTopic.ForumTopicName))
                tagList.Add(objForumTopic.ForumTopicName);
            else
            {
                tags = objForumTopic.Topic.TopicName.Split(new char[] { ' ' });
                foreach (string tag in tags)
                {
                    if (!StopWords.stopWordsList.Contains(tag.ToLower()))
                    {
                        if (tag.Length >= 3)
                        {
                            tagList.Add(tag);
                        }
                    }
                }
            }

            //Add tags of a title
            tags = objPostDetail.PostTitle.Split(new char[] { ' ' });
            foreach (string tag in tags)
            {

                if (!StopWords.stopWordsList.Contains(tag.ToLower()))
                {
                    if (tag.Length >= 3)
                    {
                        tagList.Add(tag);
                    }
                }
            }
            string strTagList = string.Join(", ", tagList.ToArray());
            return strTagList;
        }

        //private string[] GetThreadNum()
        //{
        //    //Get thread url after post
        //    if (Browser.HtmlWeb.StatusCode == HttpStatusCode.OK)
        //    {
        //        string postUrl = Browser.Response.ResponseUri.AbsoluteUri.Replace(ForumUrl, "");
        //        //if postUrl contains "/" at first position then remove it
        //        if (postUrl.Substring(0, 1).Contains("/"))
        //            postUrl = postUrl.Substring(1);

        //        //Check postUrl is a link of the post?
        //        string[] words = objPostDetail.PostTitle.Split(new char[] { ' ' });
        //        string pattern = "(" + string.Join("|", words) + ")";
        //        Regex r = new Regex(pattern.ToLower().Trim());
        //        MatchCollection mc = r.Matches(postUrl.ToLower().Trim());
        //        if (mc.Count > 2)
        //        {

        //        }
        //        else //If not found post in return url 
        //        {
        //            pattern = @"showthread\.php\?p\=(?<threadId>[0-9]+)";
        //            r = new Regex(pattern);
        //            Match m1 = r.Match(postUrl.ToLower().Trim());
        //            if (m1.Success)
        //            {
        //                threadNum = m1.Result("${threadId}");
        //            }
        //            else //Search my post
        //            {
        //                ForumTemplateDetail obj = new ForumTemplateDetail();
        //                string statisticUrl = obj.GetStatisticUrl(ForumId, ForumTypeId);
        //                DataTable myTable = GeneralClass.CreateSearchForumThreadDataTable();

        //                statisticUrl = statisticUrl.Replace("[userid]", UserId.Value.ToString());
        //                myTable = Browser.SearchNewestThread(ForumUrl, statisticUrl, myTable);
        //                if (myTable != null)
        //                {
        //                    if (myTable.Rows.Count > 0)
        //                    {
        //                        //Get first row for newest post
        //                        postUrl = myTable.Rows[0]["Url"].ToString();
        //                        //Check postUrl is a link of the post?
        //                        words = objPostDetail.PostTitle.Split(new char[] { ' ' });
        //                        pattern = "(" + string.Join("|", words) + ")";
        //                        r = new Regex(pattern.ToLower().Trim());
        //                        mc = r.Matches(postUrl.ToLower().Trim());
        //                        if (mc.Count > 2)
        //                        {
        //                            threadNum = myTable.Rows[0]["ThreadNum"].ToString();
        //                            threadPostId = myTable.Rows[0]["PostNum"].ToString();
        //                        }
        //                    }
        //                }
        //            }
        //            //phpbb3: .//ul[@class='topiclist topics']/li//dt[@title='New posts']/a[@class='topictitle']
        //            //ipb .//tr[contains(@id, 'trow_')]/td[@class='short altrow']/a[@class='_hovertrigger']
        //        }

        //        //Get threadPostId
        //        if (string.IsNullOrEmpty(threadPostId))
        //        {
        //            pattern = @"\#post(?<postnum>[0-9]+)";
        //            r = new Regex(pattern);
        //            Match m = r.Match(postUrl);
        //            if (m.Success)
        //                threadPostId = m.Result("${postnum}");
        //            else
        //                threadPostId = objForum.Browser.GetPostNum(objForum.Browser.Response.ResponseUri.AbsoluteUri);
        //        }
        //    }

        //}

        /// <summary>
        /// Search postreply .//table[contains(@id,'post')]//a[contains(@class,'bigusername')]//text()
        /// .//table[starts-with(@id, 'post')]
        /// </summary>
        /// <param name="postId"></param>
        /// <param name="forumId"></param>
        /// <param name="fId"></param>
        public void PostNewThread(int postId, int forumId)
        {
            //Get forum in database to update
            Forum objForum = dc.Forums.Single(c => c.ForumId == forumId);
            Post objPost = dc.Posts.Single(c => c.PostId == postId);
            if (objForum.DoLogin())
            {
                //dc.SubmitChanges(); //Update login status
                string title, message;
                string fValue, tagList, iconId, prefix;
                PostDetail objPostDetail;
                GetPostNewThread_HTTP(postId, forumId, out objPostDetail,
                                     out fValue, out tagList, out iconId, out prefix,
                                     out title, out message);

                //ForumTemplateDetail objForumTemplateDetail = new ForumTemplateDetail();
                //string newThreadParams = objForumTemplateDetail.GetPostNewThread_Params(objForum.ForumId, objForum.ForumTypeId);

                //======================================================================================
                //Start post new thread
                objForum.Browser.PostNewThread(objForum.ForumUrl,
                                                NewThreadUrlPattern,
                                                NewThreadParams,
                                                title,
                                                message,
                                                fValue.ToString(),
                                                iconId,
                                                tagList,
                                                prefix);

                //======================================================================================
                //Get thread num and post num in response url after post successfully
                if (objForum.Browser.HtmlWeb.StatusCode == HttpStatusCode.OK)
                {
                    objForum.SearchThreadPostNum(objPostDetail);
                    //objForum.FindThreadPostNum(objPostDetail);
                }
            }
        }

        /// <summary>
        /// Search postreply .//table[contains(@id,'post')]//a[contains(@class,'bigusername')]//text()
        /// .//table[starts-with(@id, 'post')]
        /// </summary>
        /// <param name="postId"></param>
        /// <param name="forumId"></param>
        /// <param name="fId"></param>
        public void GetPostNewThread_WebBrowser(int postId, int forumId, out PostDetail objPostDetail, out string newThreadUrl, out string fValue,
                                                out string title, out string message)
        {
            string tagList, iconId, prefix;
            GetPostNewThread_HTTP(postId, forumId, out objPostDetail,
                                 out fValue, out tagList, out iconId, out prefix,
                                 out title, out message);

            newThreadUrl = NewThreadUrlPattern;

        }
        /// <summary>
        /// Search postreply .//table[contains(@id,'post')]//a[contains(@class,'bigusername')]//text()
        /// .//table[starts-with(@id, 'post')]
        /// </summary>
        /// <param name="postId"></param>
        /// <param name="forumId"></param>
        /// <param name="fId"></param>
        public void GetPostNewThread_HTTP(int postId, int forumId, out PostDetail objPostDetail,
                                    out string fValue, out string tagList, out string iconId, out string prefix,
                                    out string title, out string message)
        {
            //init result
            title = "";
            message = "";

            fValue ="";
            tagList = "";
            iconId = "";
            prefix = "";

            //Get forum in database to update
            Forum objForum = dc.Forums.Single(c => c.ForumId == forumId);
            Post objPost = dc.Posts.Single(c => c.PostId == postId);

            //======================================================================================
            //Get f value of thread id of a forum
            ForumTopic objForumTopic = new ForumTopic();
            objForumTopic = objForumTopic.GetExactlyPostTopicValue(objForum.ForumId, objPost.TopicId);
            fValue = objForumTopic.fValue.Value.ToString();
            prefix = objForumTopic.Prefix;

            //ForumTemplateDetail objForumTemplateDetail = new ForumTemplateDetail();
            //newThreadUrl = objForumTemplateDetail.GetNewThreadUrl(objForum.ForumId, objForum.ForumTypeId);
            //string newThreadParams = objForumTemplateDetail.GetPostNewThread_Params(objForum.ForumId, objForum.ForumTypeId);

            //======================================================================================
            //Check use tag list
            if (objForum.IsTags && !string.IsNullOrEmpty(objPost.TagList))
                    tagList = objPost.TagList;

            //======================================================================================
            //Check use icon
            if (objForum.IsIcons)
            {
                int icon = objPost.GetHostIconByPost(objPost.PostId);
                if (icon > 0)
                    iconId = icon.ToString();
            }

            ////======================================================================================
            ////Check use Hide tag
            ////bool useHideTag = false;
            //if (objForum.IsHideTag)
            //    isHideTag = true;

            ////======================================================================================
            ////Check the forum contraint Hosts
            //bool isHostContraint = false;
            //if (objForum.IsHostContraint)
            //        isHostContraint = true;

            //======================================================================================
            //Get exactly PostDetail with forumtype and language of the forum
            objPostDetail = new PostDetail();
            objPostDetail = objPostDetail.GetExactlyPostDetail(objPost.PostId, objForum.LanguageId);
            if (objPostDetail == null)
            {
                //Get PostDetail with forumtype and language is English (Id=16)
                objPostDetail = dc.PostDetails.Single(p => p.PostId == postId
                                                        && p.LanguageId == (int)enumLanguage.English);
            }

            //return result
            //forumUrl = GeneralClass.GetFullUrl(objForum.ForumUrl, objForum.DefaultUrl);
            //newThreadUrl = GeneralClass.GetFullUrl(objForum.ForumUrl, newThreadUrl.Replace("[fid]", fValue.ToString()).Replace("&s=[sessionhash]", ""));

            if (objPostDetail != null)
                title = objPostDetail.PostTitle;
            
            message = objPostDetail.GetFullHtmlContent((enumForumType)objForum.ForumTypeId.Value, objForum.IsHideTag, objForum.IsHostContraint);
        }

        public void SearchThreadPostNum(PostDetail objPostDetail)
        {
            string threadNum = ""; // id value of the thread
            string postNum = ""; //id value of post in the thread

            string responseUrl = Browser.Response.ResponseUri.AbsoluteUri.Replace(ForumUrl, "");
            //if postUrl contains "/" at first position then remove it
            if (responseUrl.Substring(0, 1).Contains("/"))
                responseUrl = responseUrl.Substring(1);

            //If resquest url is different response url
            if (Browser.Request.RequestUri.AbsoluteUri != Browser.Response.ResponseUri.AbsoluteUri)
            {
                //================================================================================================
                //Step 1: Find threadnum, postnum by loading response url
                //Check response url is a links of a post
                if (objPostDetail.IsThreadUrl(responseUrl))
                {
                    string[] result = new string[2];
                    result = Browser.GetThreadPostNum(Browser.HtmlDoc);//(Browser.Response.ResponseUri.AbsoluteUri);
                    threadNum = result[0];
                    postNum = result[1];
                }
            }

            //================================================================================================
            //Step 2: Find post url in statistic url if not found threadNum and postNum in Step 1
            if (string.IsNullOrEmpty(threadNum) || string.IsNullOrEmpty(postNum))
            {
                ForumTemplateDetail obj = new ForumTemplateDetail();
                string searchThreadUrl_XPath = obj.GetSearchThreadUrl_XPath(ForumId, ForumTypeId);
                
                ForumTopic objForumTopic = new ForumTopic();
                objForumTopic = objForumTopic.GetForumTopic(ForumId, objPostDetail.Post.TopicId.Value);
                //Search threads of forum topic by conditions
                responseUrl = Browser.SearchThreadsInTopic(objPostDetail.PostTitle, GeneralClass.GetFullUrl(ForumUrl, objForumTopic.ForumTopicUrl), searchThreadUrl_XPath, Account.UserName);
                string[] result = new string[2];
                result = Browser.GetThreadPostNum(responseUrl);
                threadNum = result[0];
                postNum = result[1];
            }

            SaveThreadPost(ForumId, objPostDetail, responseUrl, threadNum, postNum);
        }

        /// <summary>
        /// Find threadnum, postnum after post new thread
        /// </summary>
        /// <param name="objPostDetail"></param>
        public void FindThreadPostNum(PostDetail objPostDetail)
        {
            string threadNum = ""; // id value of the thread
            string postNum = ""; //id value of post in the thread

            string responseUrl = Browser.Response.ResponseUri.AbsoluteUri.Replace(ForumUrl, "");
            //if postUrl contains "/" at first position then remove it
            if (responseUrl.Substring(0, 1).Contains("/"))
                responseUrl = responseUrl.Substring(1);

            //If resquest url is different response url
            if (Browser.Request.RequestUri.AbsoluteUri != Browser.Response.ResponseUri.AbsoluteUri)
            {
                //================================================================================================
                //Step 1: Find threadnum, postnum by loading response url
                //Check response url is a links of a post
                if (objPostDetail.IsThreadUrl(responseUrl))
                {
                    string[] result = new string[2];
                    result = Browser.GetThreadPostNum(Browser.HtmlDoc);//(Browser.Response.ResponseUri.AbsoluteUri);
                    threadNum = result[0];
                    postNum = result[1];
                }
            }

            //================================================================================================
            //Step 2: Find post url in statistic url if not found threadNum and postNum in Step 1
            if (string.IsNullOrEmpty(threadNum) || string.IsNullOrEmpty(postNum))
            {
                ForumTemplateDetail obj = new ForumTemplateDetail();
                //Get statistic url
                string statisticUrl = obj.GetStatisticUrl(ForumId, ForumTypeId);
                statisticUrl = statisticUrl.Replace("[userid]", UserId.Value.ToString());

                //Search threads of forum and get result in data table
                DataTable myTable = WGeneralClass.CreateSearchForumThreadDataTable();
                myTable = Browser.SearchForumThreads(ForumUrl, statisticUrl, "", myTable, false, true);
                if (myTable != null)
                {
                    if (myTable.Rows.Count > 0)
                    {
                        //Get first row for newest post
                        responseUrl = myTable.Rows[0]["Url"].ToString().Replace(ForumUrl, "");
                        //if postUrl contains "/" at first position then remove it
                        if (responseUrl.Substring(0, 1).Contains("/"))
                            responseUrl = responseUrl.Substring(1);

                        //Check postUrl is a link of the post?
                        if (objPostDetail.IsThreadUrl(responseUrl))
                        {
                            threadNum = myTable.Rows[0]["ThreadNum"].ToString();
                            postNum = myTable.Rows[0]["PostNum"].ToString();
                        }
                    }
                }
            }

            //================================================================================================
            //Step 3: Find post url in topic url (require topic url) if not found threadNum and postNum in Step 1 and 2
            if (string.IsNullOrEmpty(threadNum) || string.IsNullOrEmpty(postNum))
            {

            }

            SaveThreadPost(ForumId, objPostDetail, responseUrl, threadNum, postNum);
        }

        public void SaveThreadPost(int forumId, PostDetail objPostDetail, string responseUrl, string threadNum, string postNum)
        {
            //Save Thread of forum
            ForumThread objForumThread = new ForumThread
            {
                ForumId = forumId,
                ThreadTitle = objPostDetail.PostTitle,
                ThreadUrl = responseUrl,
                CreateOn = DateTime.Now,
                UpdateOn = DateTime.Now,
                IsAlive = true
            };

            //Save post of thread
            ThreadPost objThreadPost = new ThreadPost
            {
                PostDetailsId = objPostDetail.PostDetailsId,
                IsFirstPost = true,
                CreateOn = DateTime.Now,
                UpdateOn = DateTime.Now
            };

            //Get thread num
            if (!string.IsNullOrEmpty(threadNum))
                objForumThread.ThreadNum = int.Parse(threadNum);

            //get post num
            if (!string.IsNullOrEmpty(postNum))
                objThreadPost.PostNum = int.Parse(postNum);

            objForumThread.ThreadPosts.Add(objThreadPost);
            objForumThread.UpdateForumThread(objPostDetail.PostId.Value, forumId, objForumThread);
        }

        /// <summary>
        /// Search postreply .//table[contains(@id,'post')]//a[contains(@class,'bigusername')]//text()
        /// .//table[starts-with(@id, 'post')]
        /// </summary>
        /// <param name="postId"></param>
        /// <param name="forumId"></param>
        /// <param name="fId"></param>
        public void PostNewReply(int postId, int forumId, bool isQuickReply, string message)
        {
            ////LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            //Get forum in database to update
            Forum objForum = dc.Forums.Single(c => c.ForumId == forumId);
            //objForum.InitBrowserSession();

            if (objForum.DoLogin())
            {
                //dc.SubmitChanges(); //Update login status

                Post objPost = dc.Posts.Single(c => c.PostId == postId);
                //Get f value of thread id of a forum

                ForumTopic objForumTopic = new ForumTopic();
                objForumTopic = objForumTopic.GetExactlyPostTopicValue(objForum.ForumId, objPost.TopicId);

                int fValue = objForumTopic.fValue.Value;
                //Get exactly PostDetail with forumtype and language of the forum
                //ForumThread objForumThread = dc.ForumThreads.Single(p => p.PostDetail.PostId == postId
                //                                                                  && p.ForumId == forumId);
                ForumThread objForumThread = new ForumThread();
                objForumThread = objForumThread.GetForumThread(postId, forumId);
                string threadUrl = objForumThread.ThreadUrl;

                //ForumTemplateDetail objForumTemplateDetail = new ForumTemplateDetail();
                //string newReplyUrl = objForumTemplateDetail.GetNewReplyUrl(objForum.ForumId, objForum.ForumTypeId);
                //string postReplyParams = objForumTemplateDetail.GetPostReply_Params(objForum.ForumId, objForum.ForumTypeId);
                if (isQuickReply)
                {
                    //If found
                    objForum.Browser.PostNewReply(objForum.ForumUrl, threadUrl, NewReplyUrl, NewReplyParams, message);
                }
                else
                {
                    //objForum.Browser.PostNewReply(objForumThread.PostUrl, objForum.ForumUrl, message);
                }

                if (objForum.Browser.HtmlWeb.StatusCode == HttpStatusCode.OK)
                {
                    threadUrl = objForum.Browser.Response.ResponseUri.AbsoluteUri.Replace(objForum.ForumUrl, "");
                    if (threadUrl == objForumThread.ThreadUrl)
                    {

                    }
                    else
                    {

                    }

                }
            }
        }
        
        /// <summary>
        /// Search postreply .//table[contains(@id,'post')]//a[contains(@class,'bigusername')]//text()
        /// .//table[starts-with(@id, 'post')]
        /// </summary>
        /// <param name="postId"></param>
        /// <param name="forumId"></param>
        /// <param name="fId"></param>
        public void PostUpdateWithReply(int postId, int forumId, string replyMessage)
        {
            //Get forum in database to update
            Forum objForum = dc.Forums.Single(c => c.ForumId == forumId);
            //Get icon
            Post objPost = dc.Posts.Single(c => c.PostId == postId);
            ThreadPost objThreadPost = dc.ThreadPosts.Single(p => p.PostDetail.PostId == postId
                                                                && p.ForumThread.ForumId == forumId);
            
            if (objForum.DoLogin())
            {
                //dc.SubmitChanges(); //Update login status
                string newThreadUrl, title, message;
                string fValue, tagList, iconId, prefix;
                PostDetail objPostDetail;
                GetPostNewThread_HTTP(postId, forumId, out objPostDetail,
                                     out fValue, out tagList, out iconId, out prefix,
                                     out title, out message);

                //Get post edit params
                //ForumTemplateDetail objForumTemplateDetail = new ForumTemplateDetail();
                //string editParams = objForumTemplateDetail.GetPostEdit_Params(objForum.ForumId, objForum.ForumTypeId);
                
                if (objForum.Browser.EditPost(objForum.ForumUrl,
                                                objThreadPost.ForumThread.ThreadUrl,
                                                objThreadPost.PostNum.Value.ToString(),
                                                EditParams,
                                                title,
                                                message,
                                                "Update content in " + DateTime.Now.ToShortDateString(),
                                                iconId))
                {
                    //If update successful then post a new reply
                    //string newReplyUrl = objForumTemplateDetail.GetNewReplyUrl(objForum.ForumId, objForum.ForumTypeId);
                    //string postReplyParams = objForumTemplateDetail.GetPostReply_Params(objForum.ForumId, objForum.ForumTypeId);
                    objForum.Browser.PostNewReply(objForum.ForumUrl, objThreadPost.ForumThread.ThreadUrl, NewReplyUrl, NewReplyParams, replyMessage);
                }
            }
        }

        /// <summary>
        /// Search postreply .//table[contains(@id,'post')]//a[contains(@class,'bigusername')]//text()
        /// .//table[starts-with(@id, 'post')]
        /// </summary>
        /// <param name="postId"></param>
        /// <param name="forumId"></param>
        /// <param name="fId"></param>
        public void PostUpdateWithoutReply(int forumId, int postId)
        {
             //Get forum in database to update
            Forum objForum = dc.Forums.Single(c => c.ForumId == forumId);
            //Get icon
            Post objPost = dc.Posts.Single(c => c.PostId == postId);
            ThreadPost objThreadPost = dc.ThreadPosts.Single(p => p.PostDetail.PostId == postId
                                                                && p.ForumThread.ForumId == forumId);

            if (objForum.DoLogin())
            {
                //dc.SubmitChanges(); //Update login status
                string newThreadUrl, title, message;
                string fValue, tagList, iconId, prefix;
                PostDetail objPostDetail;
                GetPostNewThread_HTTP(postId, forumId, out objPostDetail,
                                     out fValue, out tagList, out iconId, out prefix,
                                     out title, out message);

                //Get post edit params
                //ForumTemplateDetail objForumTemplateDetail = new ForumTemplateDetail();
                //string editParams = objForumTemplateDetail.GetPostEdit_Params(objForum.ForumId, objForum.ForumTypeId);

                objForum.Browser.EditPost(objForum.ForumUrl,
                                        objThreadPost.ForumThread.ThreadUrl,
                                        objThreadPost.PostNum.Value.ToString(),
                                        EditParams,
                                        title,
                                        message,
                                        "Update content in " + DateTime.Now.ToShortDateString(),
                                        iconId);
            }
        }

        public bool DoLogin()
        {
            LoginStatus = false;
            try
            {
                if (Account == null) //If not exists account
                    return LoginStatus;

                //ForumTemplateDetail obj = new ForumTemplateDetail();
                //string loginUrl = obj.GetLoginUrl(_ForumId, _ForumTypeId);
                //string postParams = obj.GetLogin_Params(_ForumId, _ForumTypeId);
                LoginStatus = Browser.DoLogin(ForumUrl, LoginUrlPattern, LoginParams, Account.UserName, Account.Password);
                dc.SubmitChanges();
                ////Get userid
                //if (!UserId.HasValue
                //    || UserId.Value == -1)
                //    UserId = Browser.GetUserIdAfterLogin();

                //LoginDate = DateTime.Now;
                //if (LoginStatus == 1) //Successful
                //    result = true;
                //else if (LoginStatusId == -1)
                //    LoginStatusId = null;

            }
            catch (WebException we)
            {
                ErrorReport = we.Message;
                //LoginStatusId = 3;
            }
            catch (Exception ex)
            {
                ErrorReport = ex.Message;
                //LoginStatusId = 3;
            }
            return LoginStatus;
        }

        /// <summary>
        /// Get userId of account in a forum
        /// </summary>
        /// <param name="forumUrl"></param>
        /// <param name="userName"></param>
        /// <param name="doc"></param>
        /// <returns></returns>
        public int? GetUserId()
        {
            //If not exists then find and save into database
            if (!UserId.HasValue
                || UserId == -1
                || UserId == 0)
            {
                //Load homepage again
                Browser.Get(ForumUrl + "/" + DefaultUrl);
                UserId = Browser.GetUserId(ForumUrl, Account.UserName);
            }

            return UserId;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="forumThreadId"></param>
        /// <param name="postDetailsId"></param>
        public void UpdatePostNum(int forumThreadId, int postDetailsId)
        {
            //LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            ThreadPost objThreadPost = dc.ThreadPosts.Single(p => p.ForumThreadId == forumThreadId && p.PostDetailsId == postDetailsId);
            string threadUrl = GeneralClass.GetFullUrl(ForumUrl, objThreadPost.ForumThread.ThreadUrl);
            string[] result = new string[2];
            result = Browser.GetThreadPostNum(threadUrl);
            if (result[1] != string.Empty)
            {
                objThreadPost.PostNum = int.Parse(result[1]);
                dc.SubmitChanges();
            }
        }

        /// <summary>
        /// Get userId of account in a forum
        /// </summary>
        /// <param name="forumUrl"></param>
        /// <param name="userName"></param>
        /// <param name="doc"></param>
        /// <returns></returns>
        public void CheckForumThreads(int forumThreadId)
        {
            //LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            ForumThread objForumThread = dc.ForumThreads.Single(p => p.ForumThreadId == forumThreadId);
            string threadUrl = GeneralClass.GetFullUrl(ForumUrl, objForumThread.ThreadUrl);
            try
            {
                HtmlDocument doc = Browser.Get(threadUrl);
                if (Browser.Response.StatusCode == HttpStatusCode.OK)
                    objForumThread.IsAlive = true;
                else
                    objForumThread.IsAlive = false;
            }
            catch
            {
                objForumThread.IsAlive = false;
            }
            dc.SubmitChanges();
        }

        /// <summary>
        /// Get content of forum:
        /// 1. Indentify type of a forum: vBulletin, phpbb2, phpbb3, IPB
        /// 2. Indentify language of a forum
        /// 3. Indentify content of a forum: App, App-Porn, Porn, ...
        /// 4. Indentify exactly forum type of a forum include version: vBulletin x.x.x, phpbb2, phpbb3, IP.Board x.x.x
        /// 5. Indentify statistics numbers of a forum: Total threads, posts, members, current members, current guests
        /// </summary>
        public void CheckForumInfo(int forumId)
        {
            //LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            //Get forum in database to update
            Forum objForum = dc.Forums.Single(c => c.ForumId == forumId);
            try
            {
                //*********************************************************************************
                //GET ALEXA RANK & LOCATION
                //*********************************************************************************
                objForum.UpdateAlexaRankAndLocation();
                if (!objForum.IsApproved)
                {
                    //reset forumtype to check again
                    //objForum.ForumTypeId = (int)enumForumType.Unknown;

                    //Start load home page
                    string defaultUrl = objForum.DefaultUrl == null ? string.Empty : objForum.DefaultUrl;
                    HtmlAgilityPack.HtmlDocument doc = objForum.Browser.Get(objForum.ForumUrl + "/" + defaultUrl);
                    StatusCode status = new StatusCode();
                    objForum.StatusCodeId = status.GetStatusCodeId((int)objForum.Browser.HtmlWeb.StatusCode);
                    if (objForum.Browser.HtmlWeb.StatusCode == HttpStatusCode.OK)
                    {
                        string responeUrl = GeneralClass.FormatUrl(objForum.Browser.Response.ResponseUri.AbsoluteUri);
                        //Update ForumUrl again if change
                        if (objForum.ForumUrl != responeUrl)
                            objForum.ForumUrl = responeUrl;

                        //*********************************************************************************
                        //GET FORUM TYPE
                        //*********************************************************************************
                        if (objForum.ForumTypeId == (int)enumForumType.Unknown)
                        {
                            ForumType objForumType = new ForumType();
                            Dictionary<string, string> type = objForum.Browser.GetForumType(doc);
                            objForumType = objForumType.GetForumTypeId(type["type"]);
                            objForum.ForumTypeId = objForumType.ForumTypeId;
                            objForum.Version = type["version"];
                        }

                        //If the forum is exists
                        if (objForum.ForumTypeId.Value != (int)enumForumType.Unknown) //Unknown
                        {
                            //*********************************************************************************
                            //LOGIN
                            //*********************************************************************************
                            if (objForum.DoLogin()){
                                //responeUrl = GeneralClass.FormatUrl(objForum.Browser.Response.ResponseUri.AbsoluteUri);
                                //if (objForum.ForumUrl != responeUrl)
                                //    doc = objForum.Browser.Get(objForum.ForumUrl + "/" + defaultUrl);
                                //GET USER ID OF ACCOUNT
                                objForum.UserId = objForum.GetUserId();
                            }

                            //*********************************************************************************
                            //GET LANGUAGE
                            //*********************************************************************************
                            BrowserSession_General objGeneral = new BrowserSession_General();
                            if (objForum.LanguageId == (int)enumLanguage.Unknown)
                            {
                                //Get texts in forum
                                string htmlText = doc.GetContentText();
                                //User Google Translation to get Language and translated content
                                string[] translateInfo = objGeneral.TranslateContent(htmlText, 500, "auto", "en");
                                Language lang = new Language();
                                objForum.LanguageId = lang.GetLangId(translateInfo[0]);
                            }

                            //*********************************************************************************
                            //GET CONTENT: App, App-Porn, Porn
                            //*********************************************************************************
                            if (objForum.ContentTypeId == (int)enumContentType.Unknown)
                            {
                                int contentTypeId = (int)enumContentType.Unknown;
                                //Get blacklist pattern of links in forum 
                                ForumTemplateDetail objForumTemplateDetail = new ForumTemplateDetail();
                                //string searchThreadXpath = objForumTemplateDetail.GetSearchThreadsPatternParams(objForum.ForumId, objForum.ForumTypeId);
                                //Get topic links in forum
                                //Dictionary<string, string> forumLinks = objForum.Browser.SearchThreads(doc, searchThreadXpath);
                                //if (forumLinks.Count() == 0)
                                //{
                                    //string blackListPattern = objForumTemplateDetail.GetBlackListUrl(objForum.ForumId, objForum.ForumTypeId);
                                    //forumLinks = objForum.Browser.GetAllLinks(doc, blackListPattern);
                                //}

                                //string xPathLink = objForumTemplateDetail.GetXPathLink(objForum.ForumId, objForum.ForumTypeId);
                                string blackListUrl = objForumTemplateDetail.GetBlackList_Pattern(objForum.ForumId, objForum.ForumTypeId);
                                Dictionary<string, string> forumLinks = doc.GetAllLinks(objForum.ForumUrl, blackListUrl);
                                if (forumLinks.Count() > 0)
                                {
                                    string transContent = string.Join(" ", forumLinks.Values.ToArray()).ToLower();
                                    transContent = System.Web.HttpUtility.HtmlDecode(transContent).Replace("&", "");
                                    //Nếu không phải là ngôn ngữ English thì translate lại
                                    if (objForum.LanguageId != (int)enumLanguage.English)
                                        transContent = objGeneral.TranslateContent(transContent, 500, "auto", "en")[2];
                                    ContentType cType = new ContentType();
                                    if (objForum.AccountId.HasValue) //1. Nếu có account ở forum
                                    {
                                        contentTypeId = cType.IdentifyForumContent(transContent);
                                    }
                                    else //2. Nếu chưa có account login
                                    {
                                        //Vào trang login của forum để xem có tồn tại trang login này không
                                        if (objForum.ForumTypeId.HasValue)
                                        {
                                            string loginUrl = objForumTemplateDetail.GetLoginUrl(objForum.ForumId, objForum.ForumTypeId);
                                            HtmlAgilityPack.HtmlDocument loginDoc = objForum.Browser.Get(objForum.ForumUrl + "/" + loginUrl);
                                            //2.1 Sau khi vào trang login, kiểm tra xem trang login có chứa 'username' và 'password' không?
                                            if (objForum.Browser.HtmlWeb.StatusCode == HttpStatusCode.OK)
                                                contentTypeId = cType.IdentifyForumContent(transContent);
                                        }
                                    }
                                }
                                objForum.ContentTypeId = contentTypeId;
                            }

                            //*********************************************************************************
                            //Get statistics numbers: total threads, post, members, current members, current guest
                            //*********************************************************************************
                            //GetStatisticsNumbers(doc);
                        }
                    }
                }
            }
            catch (WebException we)
            {
                objForum.ErrorReport = we.Message;
            }
            catch (Exception ex)
            {
                objForum.ErrorReport = ex.Message;
            }

            try
            {
                dc.SubmitChanges();
            }
            catch (ChangeConflictException e)
            {
                //throw new ChangeConflictException(e.Message);
                throw e;
            }
        }


        /// <summary>
        /// Get content of forum:
        /// 1. Indentify type of a forum: vBulletin, phpbb2, phpbb3, IPB
        /// 2. Indentify language of a forum
        /// 3. Indentify content of a forum: App, App-Porn, Porn, ...
        /// 4. Indentify exactly forum type of a forum include version: vBulletin x.x.x, phpbb2, phpbb3, IP.Board x.x.x
        /// 5. Indentify statistics numbers of a forum: Total threads, posts, members, current members, current guests
        /// </summary>
        public Forum CheckForumInfoBySearchEngine(string forumUrl)
        {
            //LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            Forum objForum = new Forum();
            objForum.ForumId = -1;
            objForum.ForumUrl = forumUrl;
            try
            {
                //Check if Forum is Exist
                objForum = dc.Forums.Single(c => c.ForumUrl == forumUrl);
                if (objForum != null)
                    return objForum;
            }
            catch
            {

            }
            
            try
            {
                //Reset Info
                objForum.ForumTypeId = (int)enumForumType.Unknown;
                objForum.Version = "";
                objForum.ContentTypeId = (int)enumContentType.Unknown;
                objForum.LanguageId = null;

                HtmlAgilityPack.HtmlDocument doc = objForum.Browser.Get(objForum.ForumUrl + "/index.php");
                StatusCode status = new StatusCode();
                objForum.StatusCodeId = status.GetStatusCodeId((int)objForum.Browser.HtmlWeb.StatusCode);
                if (objForum.Browser.HtmlWeb.StatusCode == HttpStatusCode.OK)
                {
                    string responeUrl = GeneralClass.FormatUrl(objForum.Browser.Response.ResponseUri.AbsoluteUri);
                    //Update ForumUrl again if change
                    if (objForum.ForumUrl != responeUrl)
                        objForum.ForumUrl = responeUrl;

                    //*********************************************************************************
                    //GET FORUM TYPE
                    //*********************************************************************************
                    ForumType fType = new ForumType();
                    Dictionary<string, string> type = objForum.Browser.GetForumType(doc);
                    fType = fType.GetForumTypeId(type["type"]);
                    objForum.ForumTypeId = fType.ForumTypeId;
                    objForum.Version = type["version"];

                    //*********************************************************************************
                    //GET ALEXA RANK & LOCATION
                    //*********************************************************************************
                    objForum.UpdateAlexaRankAndLocation();

                }
            }
            catch (WebException ex)
            {
                Console.WriteLine(ex.Message);
            }
            return objForum;
        }

        /// <summary>
        /// Get alexa rank and location of a forum
        /// </summary>
        public void UpdateAlexaRankAndLocation()
        {
            //*********************************************************************************
            //GET ALEXA RANK & LOCATION
            //*********************************************************************************
            BrowserSession_General objGeneral = new BrowserSession_General();
            Dictionary<string, string> alexa = objGeneral.GetAlexaRank(ForumUrl);
            if (alexa["rank"] != "")
                AlexaRank = int.Parse(alexa["rank"]);
            if (alexa["location"] != "")
            {
                Location loc = new Location();
                LocationId = loc.GetLocationId(alexa["location"]);
            }
        }

        public void ChangeGroup(int forumId, int groupId)
        {
            //LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            //Get forum in database to update
            Forum objForum = dc.Forums.Single(c => c.ForumId == forumId);
            objForum.GroupId = groupId;
            dc.SubmitChanges();
        }

        /// <summary>
        /// Approve forum
        /// </summary>
        /// <param name="forumId"></param>
        /// <param name="groupId"></param>
        public void ChangeApprove(int forumId, bool value)
        {
            //LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            //Get forum in database to update
            Forum objForum = dc.Forums.Single(c => c.ForumId == forumId);
            objForum.IsApproved = value;
            dc.SubmitChanges();
        }

        public void FormatUrl(int forumId)
        {
            //LinqDataClassesDataContext dc = new LinqDataClassesDataContext();
            //Get forum in database to update
            Forum objForum = dc.Forums.Single(c => c.ForumId == forumId);
            objForum.ForumUrl = GeneralClass.FormatUrl2(objForum.ForumUrl);
            dc.SubmitChanges();
        }

        /// <summary>
        /// Load forum page:
        /// 1. Load default page
        /// 2. Login if have an account
        /// 3. If login is succesful then load default page again 
        /// </summary>
        /// <returns></returns>
        public HtmlDocument LoadForum()
        {
            HtmlAgilityPack.HtmlDocument doc = null;
            if (DoLogin())
            {
                doc = Browser.Get(ForumUrl + "/" + DefaultUrl);
                if (Browser.HtmlWeb.StatusCode == HttpStatusCode.OK)
                    return doc;
            }
            return null;
        }


    }

    public partial class Forum
    {
        private string _loginUrlPattern = "";
        public string LoginUrlPattern
        {
            get
            {
                if (_loginUrlPattern == "")
                {
                    ForumTemplateDetail obj = new ForumTemplateDetail();
                    _loginUrlPattern = obj.GetLoginUrl(_ForumId, _ForumTypeId);
                }
                return _loginUrlPattern;
            }
        }

        private string _loginParams = "";
        public string LoginParams
        {
            get
            {
                if (_loginParams == "")
                {
                    ForumTemplateDetail obj = new ForumTemplateDetail();
                    _loginParams = obj.GetLogin_Params(_ForumId, _ForumTypeId);
                }
                return _loginParams;
            }
        }
        private string _newThreadUrlPattern = "";
        public string NewThreadUrlPattern
        {
            get
            {
                if (_newThreadUrlPattern == "")
                {
                    ForumTemplateDetail objForumTemplateDetail = new ForumTemplateDetail();
                    _newThreadUrlPattern = objForumTemplateDetail.GetNewThreadUrl(_ForumId, _ForumTypeId);
                }
                return _newThreadUrlPattern;
            }
        }

        private string _newThreadParams = "";
        public string NewThreadParams
        {
            get
            {
                if (_newThreadParams == "")
                {
                    ForumTemplateDetail objForumTemplateDetail = new ForumTemplateDetail();
                    _newThreadParams = objForumTemplateDetail.GetPostNewThread_Params(_ForumId, _ForumTypeId);
                }
                return _newThreadParams;
            }
        }

        private string _editParams = "";
        public string EditParams
        {
            get
            {
                if (_editParams == ""){
                //Get post edit params
                ForumTemplateDetail objForumTemplateDetail = new ForumTemplateDetail();
                _editParams = objForumTemplateDetail.GetPostEdit_Params(_ForumId, _ForumTypeId);
                }
                return _editParams;
            }
        }

        private string _newReplyUrl = "";
        public string NewReplyUrl
        {
            get
            {
                if (_newReplyUrl == "")
                {
                    ForumTemplateDetail objForumTemplateDetail = new ForumTemplateDetail();
                    _newReplyUrl = objForumTemplateDetail.GetNewReplyUrl(_ForumId, _ForumTypeId);
                }
                return _newReplyUrl;
            }
        }

        private string _newReplyParams;
        public string NewReplyParams
        {
            get
            {
                if (_newReplyParams == "")
                {
                    ForumTemplateDetail objForumTemplateDetail = new ForumTemplateDetail();
                    _newReplyParams = objForumTemplateDetail.GetPostReply_Params(_ForumId, _ForumTypeId);
                }
                return _newReplyParams;
            }
            
        }

        public void SubmitChanges()
        {
            dc.SubmitChanges();
        }
    }
}
